<template><h1 id="加餐六-https-浏览器如何验证数字证书" tabindex="-1"><a class="header-anchor" href="#加餐六-https-浏览器如何验证数字证书" aria-hidden="true">#</a> 加餐六｜HTTPS：浏览器如何验证数字证书？</h1>
<p>你好，我是李兵。</p>
<p>在<a href="/guide/36" target="_blank" rel="noopener noreferrer">《36｜HTTPS：让数据传输更安全》<ExternalLinkIcon/></a>这篇文章中，我们聊了下面几个问题：</p>
<ul>
<li>
<p>HTTPS 使用了对称和非对称的混合加密方式，这解决了数据传输安全的问题；</p>
</li>
<li>
<p>HTTPS 引入了中间机构 CA，CA 通过给服务器颁发数字证书，解决了浏览器对服务器的信任问题；</p>
</li>
<li>
<p>服务器向 CA 机构申请证书的流程；</p>
</li>
<li>
<p>浏览器验证服务器数字证书的流程。</p>
</li>
</ul>
<p>不过由于篇幅限制，关于“<strong>浏览器如何验证数字证书</strong>”的这个问题我们并没有展开介绍。那么今天我们就继续聊一聊这个问题。了解了这个问题，可以方便我们把完整的 HTTPS 流程给串起来，无论对于我们理解 HTTPS 的底层技术还是理解业务都是非常有帮助的。</p>
<p>因为本文是第 36 讲的延伸，所以在分析之前，我们还是有必要回顾下<strong>数字证书申请流程</strong>和<strong>浏览器验证证书</strong>的流程，同时你最好也能回顾下第 36 讲。</p>
<h2 id="数字证书申请流程" tabindex="-1"><a class="header-anchor" href="#数字证书申请流程" aria-hidden="true">#</a> 数字证书申请流程</h2>
<p>我们先来回顾下数字证书的申请流程，比如极客时间向一个 CA 机构申请数字证书，流程是什么样的呢？</p>
<p>首先极客时间填写了一张含有<strong>自己身份信息</strong>的表单，身份信息包括了自己公钥、站点资料、公司资料等信息，然后将其提交给了 CA 机构；CA 机构会审核表单中内容的真实性；审核通过后，CA 机构会拿出自己的私钥，对表单的内容进行一连串操作，包括了对明文资料进行 Hash 计算得出信息摘要， 利用 CA 的私钥加密信息摘要得出数字签名，最后将数字签名也写在表单上，并将其返还给极客时间，这样就完成了一次数字证书的申请操作。</p>
<p>大致流程你也可以参考下图：</p>
<p><img src="https://static001.geekbang.org/resource/image/f5/a6/f569c80f8f4b25b3bf384037813cdca6.png" alt="数字证书申请过程"></p>
<h2 id="浏览器验证证书的流程" tabindex="-1"><a class="header-anchor" href="#浏览器验证证书的流程" aria-hidden="true">#</a> 浏览器验证证书的流程</h2>
<p>现在极客时间的官网有了 CA 机构签发的数字证书，那么接下来就可以将数字证书应用在 HTTPS 中了。</p>
<p>我们知道，在浏览器和服务器建立 HTTPS 链接的过程中，浏览器首先会向服务器请求数字证书，之后浏览器要做的第一件事就是验证数字证书。那么，这里所说的“验证”，它到底是在验证什么呢？</p>
<p>具体地讲，浏览器需要验证<strong>证书的有效期</strong>、<strong>证书是否被 CA 吊销</strong>、<strong>证书是否是合法的 CA 机构颁发的。</strong></p>
<p>数字证书和身份证一样也是有时间期限的，所以<strong>第一部分就是验证证书的有效期</strong>，这部分比较简单，因为证书里面就含有证书的有效期，所以浏览器只需要判断当前时间是否在证书的有效期范围内即可。</p>
<p>有时候有些数字证书被 CA 吊销了，吊销之后的证书是无法使用的，所以<strong>第二部分就是验证数字证书是否被吊销了</strong>。通常有两种方式，一种是下载吊销证书列表 -CRL (Certificate Revocation Lists)，第二种是在线验证方式 -OCSP (Online Certificate Status Protocol) ，它们各有优缺点，在这里我就不展开介绍了。</p>
<p>最后，还要<strong>验证极客时间的数字证书是否是 CA 机构颁发的</strong>，验证的流程非常简单：</p>
<ul>
<li>
<p>首先，浏览器利用证书的原始信息计算出信息摘要；</p>
</li>
<li>
<p>然后，利用 <strong>CA 的公钥</strong>来解密数字证书中的<strong>数字签名</strong>，解密出来的数据也是信息摘要；</p>
</li>
<li>
<p>最后，判断这两个信息摘要是否相等就可以了。</p>
</li>
</ul>
<p><img src="https://static001.geekbang.org/resource/image/ae/08/ae7dbe9f8785441721deb1f7b316f708.png" alt="img"></p>
<p>通过这种方式就验证了数字证书是否是由 CA 机构所签发的，不过这种方式又带来了一个新的疑问：<strong>浏览器是怎么获取到 CA 公钥的？</strong></p>
<h2 id="浏览器是怎么获取到-ca-公钥的" tabindex="-1"><a class="header-anchor" href="#浏览器是怎么获取到-ca-公钥的" aria-hidden="true">#</a> 浏览器是怎么获取到 CA 公钥的？</h2>
<p>通常，当你部署 HTTP 服务器的时候，除了部署当前的数字证书之外，还需要部署 CA 机构的数字证书，CA 机构的数字证书包括了 CA 的公钥，以及 CA 机构的一些基础信息。</p>
<p>因此，极客时间服务器就有了两个数字证书:</p>
<ul>
<li>
<p>给极客时间域名的数字证书；</p>
</li>
<li>
<p>给极客时间签名的 CA 机构的数字证书。</p>
</li>
</ul>
<p>然后在建立 HTTPS 链接时，服务器会将这两个证书一同发送给浏览器，于是浏览器就可以获取到 CA 的公钥了。</p>
<p>如果有些服务器没有部署 CA 的数字证书，那么浏览器还可以通过网络去下载 CA 证书，不过这种方式多了一次证书下载操作，会拖慢首次打开页面的请求速度，一般不推荐使用。</p>
<p>现在浏览器端就有了极客时间的证书和 CA 的证书，完整的验证流程就如下图所示：</p>
<p><img src="https://static001.geekbang.org/resource/image/cb/d3/cb150e316f4847c71288a8df50bfebd3.png" alt="CA 证书"></p>
<p>我们有了 CA 的数字证书，也就可以获取得 CA 的公钥来验证极客时间数字证书的可靠性了。</p>
<p>解决了获取 CA 公钥的问题，新的问题又来了，如果这个证书是一个恶意的 CA 机构颁发的怎么办？所以我们还需要<strong>浏览器证明这个 CA 机构是个合法的机构</strong>。</p>
<h2 id="证明-ca-机构的合法性" tabindex="-1"><a class="header-anchor" href="#证明-ca-机构的合法性" aria-hidden="true">#</a> 证明 CA 机构的合法性</h2>
<p>这里并没有一个非常好的方法来证明 CA 的合法性，妥协的方案是，直接在操作系统中内置这些 CA 机构的数字证书，如下图所示：</p>
<p><img src="https://static001.geekbang.org/resource/image/43/0b/43a732eb2ba47d06fbef20c515bd990b.png" alt="操作系统内部内置 CA 数字证书"></p>
<p>我们将所有 CA 机构的数字证书都内置在操作系统中，这样当需要使用某 CA 机构的公钥时，我们只需要依据 CA 机构名称，就能查询到对应的数字证书了，然后再从数字证书中取出公钥。</p>
<p>可以看到，这里有一个假设条件，浏览器默认信任操作系统内置的证书为合法证书，虽然这种方式不完美，但是却是最实用的一个。</p>
<p>不过这种方式依然存在问题，因为在实际情况下**，CA 机构众多，因此操作系统不可能将每家 CA 的数字证书都内置进操作系统。**</p>
<h2 id="数字证书链" tabindex="-1"><a class="header-anchor" href="#数字证书链" aria-hidden="true">#</a> 数字证书链</h2>
<p>于是人们又想出来一个折中的方案，将颁发证书的机构划分为两种类型，<strong>根 CA(Root CAs)和中间 CA(Intermediates CAs)</strong>，通常申请者都是向中间 CA 去申请证书的，而根 CA 作用就是给中间 CA 做认证，一个根 CA 会认证很多中间的 CA，而这些中间 CA 又可以去认证其他的中间 CA。</p>
<p>因此，每个根 CA 机构都维护了一个树状结构，一个根 CA 下面包含多个中间 CA，而中间 CA 又可以包含多个中间 CA。这样就形成了一个证书链，你可以沿着证书链从用户证书追溯到根证书。</p>
<p>比如你可以在 Chrome 上打开极客时间的官网，然后点击地址栏前面的那把小锁，你就可以看到 <em>.geekbang.org 的证书是由中间 CA GeoTrust RSA CA2018 颁发的，而中间 CA GeoTrust RSA CA2018 又是由根 CA DigiCert Global Root CA 颁发的，所以这个证书链就是：</em>.geekbang.org—&gt;GeoTrust RSA CA2018–&gt;DigiCert Global Root CA。你可以参看下图：</p>
<p><img src="https://static001.geekbang.org/resource/image/10/b7/10616d8fc323d33bdecb09b503551cb7.png" alt="数字证书链"></p>
<p>因此浏览器验证极客时间的证书时，会先验证 *.geekbang.org 的证书，如果合法，再验证中间 CA 的证书，如果中间 CA 也是合法的，那么浏览器会继续验证这个中间 CA 的根证书。</p>
<p>到了这里，依然存在一个问题，那就是<strong>浏览器怎么证明根证书是合法的？</strong></p>
<h2 id="如何验证根证书的合法性" tabindex="-1"><a class="header-anchor" href="#如何验证根证书的合法性" aria-hidden="true">#</a> 如何验证根证书的合法性</h2>
<p>其实浏览器的判断策略很简单，它只是简单地判断这个根证书在不在操作系统里面，如果在，那么浏览器就认为这个根证书是合法的，如果不在，那么就是非法的。</p>
<p>如果某个机构想要成为根 CA，并让它的根证书内置到操作系统中，那么这个机构首先要通过 WebTrust 国际安全审计认证。</p>
<p>什么是 WebTrust 认证？</p>
<p>WebTrust 是由两大著名注册会计师协会 AICPA（美国注册会计师协会）和 CICA（加拿大注册会计师协会）共同制定的安全审计标准，主要对互联网服务商的系统及业务运作逻辑安全性、保密性等共计七项内容进行近乎严苛的审查和鉴证。 只有通过 WebTrust 国际安全审计认证，根证书才能预装到主流的操作系统，并成为一个可信的认证机构。</p>
<p>目前通过 WebTrust 认证的根 CA 有 Comodo、geotrust、rapidssl、symantec、thawte、digicert 等。也就是说，这些根 CA 机构的根证书都内置在个大操作系统中，只要能从数字证书链往上追溯到这几个根证书，浏览器就会认为使用者的证书是合法的。</p>
<h2 id="总结" tabindex="-1"><a class="header-anchor" href="#总结" aria-hidden="true">#</a> 总结</h2>
<p>好了，今天的内容就介绍到这里，下面我们总结下本文的主要内容：</p>
<p>我们先回顾了数字证书的申请流程，接着我们重点介绍了浏览器是如何验证数字证书的。</p>
<p>首先浏览器需要 CA 的数字证书才能验证极客时间的数字证书，接下来我们需要验证 CA 证书的合法性，最简单的方法是将 CA 证书内置在操作系统中。</p>
<p>不过 CA 机构非常多，内置每家的证书到操作系统中是不现实的，于是我们采用了一个折中的策略，将颁发证书的机构划分为两种类型，<strong>根 CA(Root CAs)和中间 CA(Intermediates CAs)</strong>，通常申请者都是向中间 CA 去申请证书的，而根 CA 作用就是给中间 CA 做认证，一个根 CA 会认证很多中间的 CA，而这些中间 CA 又可以去认证其他的中间 CA。</p>
<p>于是又引出了数字证书链，浏览器先利用中间 CA 的数字证书来验证用户证书，再利用根证书来验证中间 CA 证书的合法性，最后，浏览器会默认相信内置在系统中的根证书。不过要想在操作系统内部内置根证书却并不容易，这需要通过 WebTrust 认证，这个认证审核非常严格。</p>
<p>通过分析这个流程可以发现，浏览器默认信任操作系统内置的根证书，这也会带来一个问题，如果黑客入侵了你的电脑，那么黑客就有可能往你系统中添加恶意根数字证书，那么当你访问黑客站点的时候，浏览器甚至有可能会提示该站点是安全的。</p>
<p>因此，HTTPS 并非是绝对安全的，采用 HTTPS 只是加固了城墙的厚度，但是城墙依然有可能被突破。</p>
<h2 id="课后思考" tabindex="-1"><a class="header-anchor" href="#课后思考" aria-hidden="true">#</a> 课后思考</h2>
<p>今天留给你的任务是复述下浏览器是怎么验证数字证书的，如果中间卡住了，欢迎在留言区提问交流。</p>
<p>感谢阅读，如果你觉得这篇文章对你有帮助的话，也欢迎把它分享给更多的朋友。</p>
</template>
